package org.zjt.agent.compile;

import javax.annotation.processing.Processor;
import javax.tools.*;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Description:
 *
 * @author juntao.zhang
 * Date: 2018-11-01 14:18
 * @see
 */
public class JavaCompiler {

    /**
     * 字符串编译
     * @param args
     * @throws Exception
     */
    public static void main(String[] args) throws Exception {

        String code = "public class Man {\n" +
                "\tpublic void hello(){\n" +
                "\t\tSystem.out.println(\"hello world\");\n" +
                "\t}\n" +
                "}";

        javax.tools.JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector<JavaFileObject> collector = new DiagnosticCollector<>();
        JavaFileManager javaFileManager = new MyJavaFileManager(compiler.getStandardFileManager(collector, null, null));

        List<String> options = new ArrayList<>();
        options.add("-target");
        options.add("1.8");

        Pattern CLASS_PATTERN = Pattern.compile("class\\s+([$_a-zA-Z][$_a-zA-Z0-9]*)\\s*");

        Matcher matcher = CLASS_PATTERN.matcher(code);
        String cls;
        if(matcher.find()){
            cls = matcher.group(1);
        } else{
            throw new IllegalArgumentException("No such class name in " + code);
        }

        JavaFileObject javaFileObject = new CompileAndClassLoader.MyJavaFileObject(cls, code);
        Boolean result = compiler.getTask(null, javaFileManager, collector, options, null, Arrays.asList(javaFileObject)).call();


    }


    static class MyJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> {

        /**
         * Creates a new instance of ForwardingJavaFileManager.
         *
         * @param fileManager delegate to this file manager
         */
        protected MyJavaFileManager(JavaFileManager fileManager) {
            super(fileManager);
        }


    }


    static class StringSourceJavaObject extends SimpleJavaFileObject {

        private ByteArrayOutputStream outPutStream;

        private String content = null;
        public StringSourceJavaObject(String name, String content) throws URISyntaxException {
            super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension), Kind.SOURCE);
            this.content = content;
        }

        @Override
        public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
            return content;
        }

        @Override
        public OutputStream openOutputStream() throws IOException {
            outPutStream = new ByteArrayOutputStream();
            return outPutStream;
        }

        // 获取编译成功的字节码byte[]
        public byte[] getCompiledBytes(){
            return outPutStream.toByteArray();
        }
    }





    /**
     * 文件编译
     */
    public static void fileCompile() {
        // 获取系统的java编译器
        javax.tools.JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        // 指定要编译的java文件
        String fileToCompile = "/Users/juntao.zhang/dev/workspace/myproject/java-agent/java-agent-demo/src/main/java/org/zjt/agent/runtime/RuntimeAgent.java";

        // 执行编译方法
        int compilationResult = compiler.run(null, null, null, fileToCompile);
        // 返回0表示编译成功
        if (compilationResult == 0) {
            System.out.println("success");
        } else {
            System.out.println("fail");
        }
    }
}
